<?php

/* @(#) $Id: sqltable.php 3 2009-02-16 17:58:10Z mo@ilaven.net $ */

abstract class DBOSQLTable implements ArrayAccess, Countable
{
	protected $db;
	protected $name;
	protected $columns;
	protected $indexes;
	protected $changes;
	protected $commitAction;
	public $comment;
	public $exists;
	protected $hints = array();
	
	public function __construct($db, $name, $createMode)
	{
		$this->name = $name;
		$this->db = $db;
		$this->columns = array();
		$this->indexes = array();
		$this->comment = null;
		$this->commitAction = $createMode;
		$this->retrieve();
	}
	
	/* Give a hint to the underlying engine */
	public function hint($engine, $name, $value)
	{
		if(!isset($this->hints[$engine]))
		{
			$this->hints[$engine] = array();
		}
		$this->hints[$engine][$name] = $value;
	}
	
	/* Append a new column */
	public function addCol($name, $type, $length = null, $flags = null, $comment = null, $defaultValue = null)
	{
		$column = $this->createCol($name, $type, $length, $flags, $comment);
		if($column->defaultValue !== null)
		{
			$column->defaultValue = $defaultValue;
		}
		if(isset($this->columns[$column->name]))
		{
			$this->dropCol($column->name);
		}
		$this->columns[$column->name] = $column;
		$this->changes[] = array(DBCHANGE_ADDCOL, $column);
		if($column->index != DBINDEX_NONE)
		{
			$idxname = $column->name;
			if($column->index == DBINDEX_PRIMARY)
			{
				$idxname = 'PRIMARY KEY';
			}
			$index = array(array($column->name), $column->index, false);
			$this->indexes[$idxname] = $index;
			$this->changes[] = array(DBCHANGE_ADDINDEX, array($idxname, $index));
		}
		return $column;
	}
	
	public function replaceCol($oldName, $newName, $type, $length = null, $flags = null, $comment = null, $defaultValue = null)
	{
		$column = $this->createCol($newName, $type, $length, $flags, $comment);
		if($column->defaultValue !== null)
		{
			$column->defaultValue = $defaultValue;
		}
		unset($this->columns[$oldName]);
		$this->columns[$newName] = $column;
		$this->changes[] = array(DBCHANGE_REPLACECOL, $oldName, $column);
		return $column;
	}
	
	public function addIndex($name, $type, $column /* ... */)
	{
		if($type == DBINDEX_PRIMARY)
		{
			$name = 'PRIMARY KEY';
		}
		$args = func_get_args();
		array_shift($args);
		array_shift($args);
		$cols = array();
		$n = null;
		foreach($args as $col)
		{
			$cols[] = $col->name;
			$n .= ($n ? '_' : null) . $col->name;
		}
		if($name == null) $name = $n;
		$index = array($cols, $type, false);
		$this->indexes[$name] = $index;
		$this->changes[] = array(DBCHANGE_ADDINDEX, array($name, $index));
	}
	
	public function dropCol($column)
	{
		if(is_object($column))
		{
			return $this->dropCol($column->name);
		}
		if(!isset($this->columns[$column])) return false;
		/* Drop any indexes using this column */
		foreach(array_keys($this->indexes) as $idx)
		{
			if(in_array($column, $this->indexes[$idx][0]))
			{
				$this->indexes[$idx][2] = true;
				$this->changes[] = array(DBCHANGE_DROPINDEX, $idx);
			}
		}
		$this->columns[$column]->dropped = true;
		if($this->exists)
		{
			$this->changes[] = array(DBCHANGE_DROPCOL, $column);
		}
	}
	
	public function dropIndex($index)
	{
		if(!strlen($index)) $index = 'PRIMARY KEY';
		if(!isset($this->indexes[$index])) return false;
		$this->indexes[$index][2] = true;
		$this->changes[] = array(DBCHANGE_DROPINDEX, $index);
	}
	
	public function getColumns()
	{
		return $this->columns;
	}
	
	public function getCol($column)
	{
		return (isset($this->columns[$column]) ? $this->columns[$column] : null);
	}
	
	public function commit()
	{
		if($this->commitAction == DBCREATE_NOTEXISTS || $this->commitAction == DBCREATE_DROP)
		{
			return $this->create();
		}
		return $this->applyChanges();
	}
	
	public function append($newval)
	{
		return $this->db->insert($this->name, $newval, true);
	}
	
	public function count()
	{
		return $this->db->getOne('SELECT COUNT(*) FROM ' . $this->name);
	}
	
	public function offsetExists($index)
	{
		return false;
	}

	public function offsetGet($index)
	{
		return null;
	}
	
	public function offsetSet($index, $value)
	{
		if($index == null)
		{
			return $this->append($value);
		}
		echo "offsetSet: index = $index\n";
		print_r($value);
		return null;
	}
	
	public function offsetUnset($index)
	{
	}
	
}
